
;*******************************************************
;
;	SCSI Driver 'Main Driver'.
;
;	Written by Matt Gulick.		Started May 25,1988
;
;	Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************

;*******************************************************
;
;	This file contains the 'Main Driver' as defined in
;	the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************

;	May 25,		1988	File started.
;	June 6,		1988	Turned sections into subroutines
;						and wrote the Main Driver Proper.
;	June 20,	1988	Added Register Input and Output.
;						Also included the changes from
;						the code review.
;	Oct  25,	1988	Made changes in code to reflect the
;						redesign of the SCSI Manager interface.
;

					STRING		PASCAL
					BLANKS		OFF
					PAGESIZE	70
					PRINT		NOGEN
					PRINT		NOMDIR
					MACHINE		M65816

					IMPORT		cmd_t_tbl
					IMPORT		call_type
					IMPORT		scratch0
					IMPORT		cmd_ps_tbl
					IMPORT		c_len_len
					IMPORT		c_blk_len
					IMPORT		divide
					IMPORT		result
					IMPORT		divend
					IMPORT		divsor
					IMPORT		time_cnt
					IMPORT		rout2_s_disp
					IMPORT		gsos_dpage
					IMPORT		f_partition
					IMPORT		internal
					IMPORT		disk_switch
					IMPORT		scsi_mgrnum
					IMPORT		manager_cmd
					IMPORT		cur_cmd
					IMPORT		cur_cmd2
					IMPORT		cur_group
					IMPORT		trans_dest
					IMPORT		p_block_num
					IMPORT		killer_blk
					IMPORT		trans_flag
					IMPORT		temp_x
					IMPORT		temp_y
					IMPORT		timeout_flag
					IMPORT		auto_sense_data
					IMPORT		lst_rslt_ec
					IMPORT		lst_rslt_stat
					IMPORT		lst_rslt_skey
					IMPORT		lst_rslt_info
					IMPORT		lst_rslt_rqlen
					IMPORT		lst_rslt_scode

					PRINT		OFF

					INCLUDE		'scsihd.equates'
					INCLUDE		'M16.MEMORY'
					INCLUDE		'M16.UTIL'

					PRINT		ON

					EJECT

;*******************************************************
;
;	Main Entry point to the 'Main Driver'.
;
;	The function of this code is to take the callers
;	command data and build a SCSI Command Packet.  This
;	is done using the conversion tables in the file
;	'SCSI Command Table'.  The command and other data
;	is actually built in the space that has been added
;	to the DIB and then routed to the SCSI Manager.
;
;	The routine is called with the LONG pointer to the
;	callers command data in the Direct Page location
;	'scsi_mdrvr'.  This, in conjunction with the DIB Ptr
;	at direct page location 'dib_ptr' as the address
;	for the template overlay, will be used to do the
;	following:
;
;		Transfer the callers command data to the command
;		packet.
;			Zero all 12 bytes first.
;			Validate Internal Command flag if set.
;			.OR. in all values durring translation.
;			Adjust Transfer length if needed.
;			Convert Block Number from Logical to Actual
;				If partition Flag is  zero then leave
;				block number unmodified.
;			Check for command errors.
;
;		Stuff SCSI Manager Flags
;
;		Stuff data in the TRX buffer data structure
;
;		Ship the call out to the SCSI Manager.
;
;		Clear Partition Call Flag.
;
;		Clear the Internal Command Flag.
;
;		Translate any SCSI errors into GS/OS errors.
;
;	Inputs:		Acc			=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	Acc			=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		Carry set if Error.
;
;*******************************************************

					EXPORT	main_drvr
main_drvr			PROC
												;
												; Clear the Timeout flag
												;
					stz		|timeout_flag
												;
												; Clear the last error stuff
												;
					stz		|lst_rslt_ec
					stz		|lst_rslt_stat
					stz		|lst_rslt_skey
					stz		|lst_rslt_info
					stz		|lst_rslt_rqlen
					stz		|lst_rslt_scode
												;
												; Clear the Command Buffer
												;
					ldx		#max_cmd_len*2\
							-2
					ldy		#max_cmd_len*2\
							+dib.scsicmd\
							-2
					lda		#$0000
@loop				sta		[dib_ptr],y
					dey
					dey
					dex
					dex
					bpl		@loop
												;
												; Get the Curren CoMmanD and GRouP
												;
					lda		[scsi_mdrvr]
					and		#$0fff
					sta		|cur_cmd2			;Preserve Current Command Number
					and		#$00ff
					sta		|cur_cmd			;Preserve Current Command Number
					pha
												;
												; Get Offsets to Validate Command
												; Support by the device.
												;
					tax
					and		#bit_4\
							+bit_5\
							+bit_6\
							+bit_7
					lsr		a
					lsr		a
					lsr		a
					tay
					lda		|bm_cmd_offset,y
					tay
					txa
					and		#bit_0\
							+bit_1\
							+bit_2\
							+bit_3
					asl		a
					tax
					lda		[dib_ptr],y
					and		|bm_cmd_mask,x
					bne		@cmd_support
												;
												; Command Not Supported
												; by this device.
												;
					pla							;Fix Stack
					lda		#drvr_bad_code
					sec
@exit				rts
												;
												; Get the SCSI Group Number.
												;
@cmd_support		pla
					and		#bit_5\
							+bit_6\
							+bit_7
					lsr		a
					lsr		a
					lsr		a
					lsr		a
					lsr		a
					sta		|cur_group
												;
												; Set TRANSlation PoiNTer
												;
					jsr		s_trans_ptr
					bcs		@exit
												;
												; VALidate the CoMmanD TYPe
												;
					jsr		val_cmd_typ
					bcs		@exit				;Bad Command
												;
												; Set 'scsi_zp4' to scsi Command
												; in DIB
												;
					clc
					lda		<dib_ptr
					adc		#dib.scsicmd
					sta		<scsi_zp4
					lda		<dib_ptr+2
					adc		#$0000
					sta		<scsi_zp4+2
												;
												; TRANSLATE user's command data
												; into SCSI Command Packet
												;
					jsr		translate
												;
												; FINALIZE the SCSI Command Packet.
												; This includes updating the
												; requested block number to account
												; for partitioning, and the request
												; length from bytes to blocks.
												;
					jsr		finalize
					bcs		@exit
					bvs		@no_data
												;
												; Stuff SCSI Manager flags.
												;
					jsr		stuff_flag
												;
												; Build the Transmit/Receive
												; structure.
												;
					lda		#scsi_io_call		;set SCSI Manager Command to
					sta		|manager_cmd		;I/O Call.

					ldy		#dib.trx_buff		;Stuff the Buffer Pointer
					lda		<buff_ptr
					sta		[dib_ptr],y

					ldy		#dib.trx_buff+2
					lda		<buff_ptr+2
					sta		[dib_ptr],y
											;
											; Stuff the request count in both the
											; Total length and in the DCMove command.
											;
					lda		<rqst_cnt

					ldy		#dib.trx_length		;Stuff the DCMove transfer count
					sta		[dib_ptr],y

					ldy		#dib.trx_rqst		;Stuff the Requested transfer count
					sta		[dib_ptr],y

					lda		<rqst_cnt+2

					ldy		#dib.trx_length+2
					sta		[dib_ptr],y

					ldy		#dib.trx_rqst+2
					sta		[dib_ptr],y
											;
											; Mark auto sense buffer as trashed.
											;
					lda		#$ffff
					sta		|auto_sense_data
					sta		|auto_sense_data+2
											;
											; Send command to the SCSI Manager
											;
					jsr		issue_cmd
											;
											; Place Info in for Get Last Result
											; Status Call.
											;
					php
					pha

					sta		|lst_rslt_stat
											;
											; Did we get auto sense data?
											;
					lda		|auto_sense_data
					and		|auto_sense_data+2
					cmp		#$ffff
					beq		@no_sense		;No.
											;
											; Yes we did.  Setup last result
											; info incase it is needed.
											;
					lda		|auto_sense_data+\
							rqst_sens.sense_key
					and		#$00ff
					sta		|lst_rslt_skey

					lda		|auto_sense_data+\
							rqst_sens.info_bytes
					sta		|lst_rslt_info
					lda		|auto_sense_data+\
							rqst_sens.info_bytes+2
					sta		|lst_rslt_info+2

					clc
					lda		|auto_sense_data+\
							rqst_sens.addnl_sens_len
					and		#$00ff
					adc		#$0008
					sta		|lst_rslt_rqlen

					lda		|auto_sense_data+\
							rqst_sens.addnl_sens_code
					and		#$00ff
					sta		|lst_rslt_scode
											;
											; Restore Acc. Carry and Stack.
											;
@no_sense			pla
					plp
											;
											; Clear partiton call and internal
											; command flags.
											;
@no_data			stz		|f_partition
					stz		|internal
											;
											; return to Driver front end.
											;
					rts

;*******************************************************
;
; Transfer the callers command data to the command
; packet.
;
;*******************************************************

;*******************************************************
;*******************************************************
;
;	Subroutines from the Main Driver.
;
;*******************************************************
;*******************************************************

					EJECT
			
;*******************************************************
;
;	Point to Command Translation Table
;		'trans_flag'	=	Translation Flags
;		'scsi_zp2'		=	Translation Data.
;
;*******************************************************


s_trans_ptr			lda		#cmd_t_tbl
					sta		<scsi_zp2
										;
										; Find Command Translation Table for conversion
										;
@find_cmd			lda		(scsi_zp2)
					bmi		@chk_end
					cmp		|cur_cmd	;Check for 8 bits of 16 match
					beq		@got_r_cmd
					cmp		|cur_cmd2	;Check for 12 bits of 16 match
					beq		@got_r_cmd
										;
										; Goto next entry.
										;
					clc
					lda		<scsi_zp2
					adc		#$0004
					sta		<scsi_zp2
					bra		@find_cmd
										;
										; Is it really the end of the table?
										;
@chk_end			cmp		#$ffff
					beq		@no_cmd_fnd
										;
										; The Command was not found.
										; Return a Bad Command error
										;
@no_cmd_fnd			lda		#drvr_bad_code
					sec
					rts
										;
										; We found our command.  Now
										; point to the translation data.
										;
@got_r_cmd			ldy		#$0002
					lda		(scsi_zp2),y
					sta		<scsi_zp2
										;
										; Now get the Translation Flags.
										;
					lda		(scsi_zp2)
					sta		|trans_flag
										;
										; Set Timeout Factor.
										;
@check_timer		and		#scsic_tout
					beq		@not_by_block

					dec		|timeout_flag

@not_by_block		ldy		#$0002
					lda		(scsi_zp2),y
					ldy		#dib.time_out
					sta		[dib_ptr],y
										;
										; Advance pointer to translation data
										;
					clc
					lda		<scsi_zp2
					adc		#$0004			;Setup Pointer to translation data
					sta		<scsi_zp2
					rts

					EJECT
			
;*******************************************************
;
;	Check to see if this is an internal command.  If it
;	is, then the high of 'internal' must be set.
;
;	Validate that this command is a Staus Command if we
;	were called with a Status type call.  Or is it a
;	Control call with a Control Command?
;
;*******************************************************


val_cmd_typ			stz		|disk_switch		;Ensure that this flag is clear.

					lda		|trans_flag
					tay
					and		#scsic_int
					beq		@non_int		;If = then Internal Command flag = 0
					bit		|internal		;non-0.  Is it an internal command?
					bpl		@no_cmd_fnd
											;
											; Is the command a Status if entry
											; was via status, or is it a Control
											; vial control entry.  If neither
											; then error out.
											;
@non_int			tya
					and		|call_type
					beq		@no_cmd_fnd		;No match.  Error.
											;
											; Must this command be issued to the
											; first DIB of a linked device?
											;
					tya
					and		#scsic_1st
					beq		@chk_dsksw
											;
											; Check Headlink Pointer.
											;
					phy
					ldy		#dib.headlnk
					lda		[dib_ptr],y
					beq		@ply
					ldy		#dib.devnum
					cmp		[dib_ptr],y
					beq		@ply
											;
											; The Command was invalid.
											; Return a Bad Command error
											;
					ply						;Restore the stack.
@bad_dev_num		lda		#bad_dev_number
					sec
					rts
											;
											; Check to see if we need to do a
											; DISK SWITCH after this command.
											;
@ply				ply

@chk_dsksw			tya
					and		#scsic_dsw
					beq		@clc

					dec		disk_switch

@clc				clc
					rts
											;
											; The Command was invalid.
											; Return a Bad Command error
											;
@no_cmd_fnd			lda		#drvr_bad_code
					sec
@rts				rts

					EJECT
			
;*******************************************************
;
;	Is it an ASIS Command, or does it need to be
;	translated?  What ever the case, when this command
;	returns, the command data will be in it's place
;	ready for the length and block fields to be updated
;	in needed.
;
;*******************************************************


translate			lda		|trans_flag
					and		#scsid_asis
					beq		@translate
										;
										; Yes. It is as is.  Move the Command
										; bytes over.
										;
					ldy		#max_cmd_len-2
@move_cmd			lda		[scsi_mdrvr],y
					sta		[scsi_zp4],y
					dey
					dey
					bpl		@move_cmd
@rts				rts					;Return to caller.
										;
										;
										; We have gotten to this piece of code
										; because the user data is not in the
										; form accepted by the SCSI Target.
										; We need to translate the data using
										; the translation data pointed to by
										; the direct page value 'scsi_zp2' It
										; is extremely important that we .OR.
										; in all values during translation.
										;
@translate			lda		#null		;Always do the Command Byte
					bra		@over

@loop				lda		(scsi_zp2)	;Get translation Data.
					beq		@rts		;we are at the end if value = $0000
										;
										; Place High Byte in Source Offset and
										; the Low Byte in Destination Offset.
										;
@over				tay
					and		#bit_0\
							+bit_1\
							+bit_2\
							+bit_3
					sta		|trans_dest
					tya
					xba					;Move High Byte to Low Byte
					and		#bit_0\
							+bit_1\
							+bit_2\
							+bit_3
					tay
										;
										; Move Command Data.
										;
					shortm				;We only want the byte from this
					lda		[scsi_mdrvr],y
					ldy		|trans_dest	;offset.
					ora		[scsi_zp4],y
					sta		[scsi_zp4],y
					longm
										;
										; Point to next Translation Byte
										;
					clc
					lda		<scsi_zp2
					adc		#$0002
					sta		<scsi_zp2
					bra		@loop

					EJECT
			
;*******************************************************
;
;	The command Packet is now built except for some
;	minor cosmetic work.
;
;*******************************************************
											;
											; Stuff the SCSI Device ID (Our unit
											; number) and our Slot Number into the
											; commad area for the SCSI Manager.
											;
finalize
					ldy		#dib.slotnum	;***** Temp Change *****
					lda		[dib_ptr],y		;***** Temp Change *****
					ldy		#dib.scsi_slot	;***** Temp Change *****
					sta		[dib_ptr],y		;***** Temp Change *****

					ldy		#dib.unitnum
					lda		[dib_ptr],y
					and		#max_p_mask\
							--$ffff
					ldy		#dib.scsiid
					sta		[dib_ptr],y
											;
											; Set ZP3 to point to the Command
											; Packet information.  This will be
											; used to place the length and
											; block number as well as the
											; command length for the SCSI
											; Manager.
											;
					lda		|cur_group
					asl		a				;Multiply by 6
					sta		|scratch0
					asl		a
					adc		|scratch0		;Carry Clear by asl and adc.
					adc		#cmd_ps_tbl		;Carry still Clear.
					sta		<scsi_zp3
											;
											; Adjust Transfer length if needed.
											;
					lda		trans_flag
					and		#scsid_blk++\	;Convert Trans Count to Blocks
							scsid_byte++\	;Leave Trans Count in Bytes
							scsid_none		;Transfer count does not go in CMD

					cmp		#scsid_none		;Is the Request length in the command?
					beq		@blknum_jmp		;No.
					cmp		#scsid_byte		;Yes.  Is it in Byte form?
					beq		@move_byte		;Yes.
					cmp		#scsid_blk		;No.  Is it in Block form?
					beq		@move_blk		;Yes.
					sec						;No. Return Bad Byte Count Error.
@bad_rqst			lda		#drvr_bad_cnt
@clv				clv						;Clear Overflow Flag
					rts

@blknum_jmp			jmp		@block_num		;No.
											;
											; If the request count = 0 then exit with
											; the overflow flag set.  This will indicate
											; that no data is to tbe transfered.  It
											; also indicates that this is not an error
											; condition.
											;
@zero_cnt			bit		@overflow
					clc
					rts

@overflow			dc.w	$4000
											;
											; Convert Request Count to Blocks.
											;
@move_blk			lda		<rqst_cnt		;Setup Divide Routine.
					sta		|divend

					ora		<rqst_cnt+2		;Check for zero request from block device.
					beq		@zero_cnt

					lda		<rqst_cnt+2
					sta		|divend+2

					ldy		#dib.blksize
					lda		[dib_ptr],y
					sta		|divsor

					jsr		divide
					bcs		@clv
											;
											; Get requested Length in blocks and
											; goto stuff routine. Also stuff for
											; timeout calculation if needed.
											;
					ldx		|result
					stx		|time_cnt
					ldy		|result+2
					sty		|time_cnt+2

					bra		@stuff_len
											;
											; Get requested length in bytes and goto
											; stuff routine.
											;
@move_byte			ldx		<rqst_cnt
					ldy		<rqst_cnt+2
											;
											; Clear timeout Values.
											;
					stz		|time_cnt
					stz		|time_cnt+2

;*******************************************************
;
;	Transfer request length to command packet.
;
;*******************************************************

@stuff_len			sty		|temp_y			;Save 32 bit transfer length for later
					stx		|temp_x
					short					;Goto 8 bit Acc
					ldy		#<c_len_len		;Get offset into command packet description
					lda		(scsi_zp3),y	;table and get Length of length field
					tax
											;
											; Check byte count so that any value greater
											; than the max will be represented by the
											; max.
											;
					lda		|temp_y+1
					beq		@byte_3_ok
					lda		#$ff
					stz		|temp_y+1
					sta		|temp_y
					sta		|temp_x+1
					sta		|temp_x
@byte_3_ok			cpx		#$03
					bge		@count_ok

					lda		|temp_y
					beq		@byte_2_ok
					lda		#$ff
					stz		|temp_y
					sta		|temp_x+1
					sta		|temp_x
@byte_2_ok			cpx		#$02
					beq		@count_ok

					lda		|temp_x+1
					beq		@byte_1_ok
					lda		#$ff
					stz		|temp_x+1
					sta		|temp_x
@byte_1_ok			cpx		#$01
					beq		@count_ok

					stz		|temp_x

@count_ok			dey
					lda		(scsi_zp3),y	;and the offset to the end of the length
					tay						;field
					lda		|temp_x			;Stuff the Low byte of the length
					ora		[scsi_zp4],y
					sta		[scsi_zp4],y
					dex
					beq		@exit_len		;Do Block Number.
					dey
					lda		|temp_x+1		;Stuff the Mid-Low byte of the
					ora		[scsi_zp4],y	;length if used.
					sta		[scsi_zp4],y
					dex
					beq		@exit_len		;Do Block Number.
					dey
					lda		|temp_y			;Stuff the Mid-High byte of the
					ora		[scsi_zp4],y	;length if used.
					sta		[scsi_zp4],y
					dex
					beq		@exit_len		;Do Block Number.
					dey
					lda		|temp_y+1		;Stuff the High byte of the
					ora		[scsi_zp4],y	;length if used.
					sta		[scsi_zp4],y
									;
									; Clean up Processor.
									;
@exit_len			longmx

;*******************************************************
;
;	Convert Block Number from Logical to Actual If
;	partition Flag is  zero then leave block number
;	unmodified.
;
;*******************************************************

@block_num			lda		|trans_flag		;Does it have a block number in the
					and		#scsit_blk		;command packet?
					beq		@exit_blk1		;No.
											;
											; Is this a partition Map call?
											;
					bit		|f_partition	;Get the partition call flag.
					bmi		@exit_blk1		;It's a partition map call.
											;
											; It has a block number and is not a
											; partition map command.  Translate
											; that logical block number to a
											; physical number.
											;
					ldy		#dib.start_blk+2
					lda		[dib_ptr],y
					sta		|p_block_num\	;Stored High  Low
							-dib.start_blk,y
					ldy		#dib.start_blk
					lda		[dib_ptr],y
					sta		|p_block_num\	;Stored High  Low
							-dib.start_blk,y
											;
											; Zero out starting block number space.
											; This space is used to retrieve the
											; starting block number for a call incase
											; it is needed.  An example of this is a
											; device specific write type call that is
											; going to update blocks that might be in
											; the cache.  If this happens, then this
											; will be used as a starting point from
											; whence to kill those blocks that are in
											; the cache.
											;
					stz		|killer_blk
					stz		|killer_blk+2
											;
											; We now have the block offset where we
											; need it.
											;
					short					;Goto 8 bit Acc
					ldy		#<c_blk_len		;Get offset into command packet description
					lda		(scsi_zp3),y	;table and get Length of block field
					tax
					dey
					lda		(scsi_zp3),y	;and the offset to the end of the block
					tay						;field
					clc
					lda		[scsi_zp4],y	;adjust the Low byte of block num.
					sta		|killer_blk
					adc		|p_block_num+3	;add the physical block offset.
					sta		[scsi_zp4],y
					dex
					beq		@exit_blk		;Do Block Number.
					dey
					lda		[scsi_zp4],y	;adjust the Mid-Low byte of block num.
					sta		|killer_blk+1
					adc		|p_block_num+2	;add the physical block offset.
					sta		[scsi_zp4],y
					dex
					beq		@exit_blk		;Do Block Number.
					dey
					lda		[scsi_zp4],y	;adjust the Mid-High byte of block num.
					sta		|killer_blk+2
					adc		|p_block_num+1		;add the physical block offset.
					sta		[scsi_zp4],y
					dex
					beq		@exit_blk			;Do Block Number.
					dey
					lda		[scsi_zp4],y		;adjust the High byte of block num.
					sta		|killer_blk+3
					adc		|p_block_num		;add the physical block offset.
					sta		[scsi_zp4],y
												;
												; Clean up Processor.
												;
@exit_blk			longmx
												;
												; Check for Block Number overflow
												; (Carry Set)
												;
					bcc		@exit_blk2
					lda		#drvr_bad_req
					rts
			
@exit_blk1			clc
@exit_blk2			clv							;Clear no data flag
					rts

					EJECT
			
;*******************************************************
;
;	Stuff Flags for SCSI Manager
;
;*******************************************************

stuff_flag

;-------------------------------------------------------------------------------

					IF		scsi_dtype = mcd_40	THEN
									;
									; It is a Direct Access Magnetic
									; Tape Device.
									;
					lda		#$8000

					ELSE

;-------------------------------------------------------------------------------

									;
									; It is not a Direct Access Magnetic
									; Tape Device.
									;
					lda		#$0000

					ENDIF

;-------------------------------------------------------------------------------

					ldy		#dib.scsic_flgs
					sta		[dib_ptr],y
					rts

					EJECT
			
;*******************************************************
;
;	Call the SCSI Manager VIA the Supervisory Dispatcher.
;
;*******************************************************
issue_cmd
										;
										; Set Timeout Factor.
										;
				lda		|timeout_flag
				beq		@over
										;
										; Adjust Time Out Value.
										;
				ldy		#dib.time_out
				lda		[dib_ptr],y
				sta		@time_mult

				lda		|time_cnt+2
				bne		@do_max_time
				lda		|time_cnt
				stz		|time_cnt
				beq		@do_max_time

@mult_loop		lsr		@time_mult
				bcc		@shift

				php
				clc
				adc		|time_cnt
				sta		|time_cnt
				bcs		@fix
				cmp		#max_timeout
				bge		@fix
				plp

@shift			beq		@save
				asl		a
				bcc		@mult_loop
				bra		@do_max_time

@time_mult		dc.w	null

@fix			plp

@do_max_time	lda		#max_timeout
@save			ldy		#dib.time_out
				sta		[dib_ptr],y
										;
										; Setup the pointer to our Command
										; list within the DIB on GS/OS Direct
										; Page
										;
@over			ldx		|gsos_dpage
				clc
				lda		<dib_ptr

;				adc		#dib.scsiid
				adc		#dib.scsi_slot

				sta		>smgr_pl_ptr,x
				lda		<dib_ptr+2

;				adc		#^dib.scsiid
				adc		#^dib.scsi_slot

				sta		>smgr_pl_ptr+2,x
										;
										; Call the SCSI Manager via the
										; S_DISPATCHER
										;
				lda		|scsi_mgrnum	;Get the Managers ID
				ldx		|manager_cmd	;Get Manager Command Number
				jmp		rout2_s_disp

				EJECT
										;
										; Bitmaps used to check
										; for command errors.
										;
										; Offset into DIB to where
										; the WORD is that holds the
										; bit for this group.
										;
bm_cmd_offset	dc.w	dib.group0		;group0	Low  WORD
				dc.w	dib.group0+2	;		High WORD
				dc.w	dib.group1		;group1	Low  WORD
				dc.w	dib.group1+2	;		High WORD
				dc.w	dib.group2		;group2	Low  WORD
				dc.w	dib.group2+2	;		High WORD
				dc.w	dib.group3		;group3	Low  WORD
				dc.w	dib.group3+2	;		High WORD
				dc.w	dib.group4		;group4	Low  WORD
				dc.w	dib.group4+2	;		High WORD
				dc.w	dib.group5		;group5	Low  WORD
				dc.w	dib.group5+2	;		High WORD
				dc.w	dib.group6		;group6	Low  WORD
				dc.w	dib.group6+2	;		High WORD
				dc.w	dib.group7		;group7	Low  WORD
				dc.w	dib.group7+2	;		High WORD
										;
										; Mask for commands $00 - $0F
										; in the low word and commands
										; $10 - $1F in the high word.
										;
bm_cmd_mask		dc.w	bit_7			;CMD $x0 Bit 7 Low Byte
				dc.w	bit_6			;CMD $x1 Bit 6 Low Byte
				dc.w	bit_5			;CMD $x2 Bit 5 Low Byte
				dc.w	bit_4			;CMD $x3 Bit 4 Low Byte
				dc.w	bit_3			;CMD $x4 Bit 3 Low Byte
				dc.w	bit_2			;CMD $x5 Bit 2 Low Byte
				dc.w	bit_1			;CMD $x6 Bit 1 Low Byte
				dc.w	bit_0			;CMD $x7 Bit 0 Low Byte
				dc.w	bit_15			;CMD $x8 Bit 7 High Byte
				dc.w	bit_14			;CMD $x9 Bit 6 High Byte
				dc.w	bit_13			;CMD $xA Bit 5 High Byte
				dc.w	bit_12			;CMD $xB Bit 4 High Byte
				dc.w	bit_11			;CMD $xC Bit 3 High Byte
				dc.w	bit_10			;CMD $xD Bit 2 High Byte
				dc.w	bit_9			;CMD $xE Bit 1 High Byte
				dc.w	bit_8			;CMD $xF Bit 0 High Byte

				ENDP

				EJECT

				END
